package com.byd.utils;

import java.lang.ref.WeakReference;
import android.content.Context;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.Looper;
import android.os.SystemClock;
import android.view.Gravity;
import android.view.View;
import android.view.View.OnAttachStateChangeListener;
import android.widget.TextView;
import android.widget.Toast;

public final class ToastUtils implements OnAttachStateChangeListener {
	private static WeakReference<ToastUtils> sLastToast;
	private final Toast mToast;
	private long mFinishTime = 0l;
	private final Handler mHandler = new Handler(Looper.getMainLooper());

	public abstract static class BaseBuilder<T> {
		private final T t;
		private int width;
		private int height;
		private int gravity = Gravity.NO_GRAVITY;
		private int offsetX;
		private int offsetY;
		private int duration = 2000;
		private Drawable background = null;

		private BaseBuilder() {
			t = getT();
		}

		abstract T getT();

		public T setWidth(int width) {
			this.width = width;
			return t;
		}

		public T setHeight(int height) {
			this.height = height;
			return t;
		}

		public T setGravity(int gravity, int offsetX, int offsetY) {
			this.gravity = gravity;
			this.offsetX = offsetX;
			this.offsetY = offsetY;
			return t;
		}

		/** 设置Toast显示时间
		 * 
		 * @param duration 单位ms
		 * @return 当前实例 */
		public T setDuration(int duration) {
			this.duration = duration;
			return t;
		}

		public T setBackground(Drawable background) {
			this.background = background;
			return t;
		}

		public T setBackgroundColor(int color) {
			this.background = new ColorDrawable(color);
			return t;
		}

		void configBase(ToastUtils toastUtils) {
			if(width > 0) {
				toastUtils.setWidth(width);
			}
			if(height > 0) {
				toastUtils.setHeight(height);
			}
			if(gravity != Gravity.NO_GRAVITY) {
				toastUtils.setGravity(gravity, offsetX, offsetY);
			}
			toastUtils.setDuration(duration);
			if(background == null) {
				setBackgroundColor(Color.BLACK);
			}
			toastUtils.setBackground(background);
		}

		public abstract void show();
	}

	public static final class Builder1 extends BaseBuilder<Builder1> {
		private final Context context;
		private String content;
		private int textSize;
		private int textColor = Color.WHITE;
		private int paddingLeft;
		private int paddingRight;
		private int paddingTop;
		private int paddingBottom;

		private Builder1(Context context) {
			this.context = context;
		}

		@Override
		Builder1 getT() {
			return this;
		}

		public Builder1 setText(String content) {
			this.content = content;
			return this;
		}

		public Builder1 setTextSize(int textSize) {
			this.textSize = textSize;
			return this;
		}

		public Builder1 setTextColor(int textColor) {
			this.textColor = textColor;
			return this;
		}

		public Builder1 setPadding(int left, int top, int right, int bottom) {
			paddingLeft = left;
			paddingTop = top;
			paddingRight = right;
			paddingBottom = bottom;
			return this;
		}

		@Override
		public void show() {
			final TextView textView = new TextView(context);
			final ToastUtils toastUtils = new ToastUtils(textView);
			configBase(toastUtils);
			textView.setGravity(Gravity.CENTER);
			textView.setText(content);
			if(textSize > 0) {
				textView.setTextSize(textSize);
			}
			textView.setPadding(paddingLeft, paddingTop, paddingRight, paddingBottom);
			textView.setTextColor(textColor);
			toastUtils.show();
		}
	}

	public static final class Builder2 extends BaseBuilder<Builder2> {
		private final View view;

		private Builder2(View view) {
			this.view = view;
		}

		@Override
		public Builder2 getT() {
			return this;
		}

		@Override
		public void show() {
			final ToastUtils toastUtils = new ToastUtils(view);
			configBase(toastUtils);
			toastUtils.show();
		}
	}

	private ToastUtils(View view) {
		mToast = new Toast(view.getContext());
		mToast.setView(view);
		view.addOnAttachStateChangeListener(this);
	}

	private static void cancelLast(ToastUtils current) {
		final ToastUtils toastUtils = sLastToast == null ? null : sLastToast.get();
		if(current != toastUtils) {
			if(toastUtils != null) {
				toastUtils.cancel();
			}
			sLastToast = null;
			if(current != null) {
				sLastToast = new WeakReference<ToastUtils>(current);
			}
		}
	}

	public static Builder1 create(Context context) {
		return new Builder1(context);
	}

	public static Builder2 create(View view) {
		return new Builder2(view);
	}

	private void setWidth(int w) {
		final View view = mToast.getView();
		view.setMinimumWidth(w);
	}

	private void setHeight(int h) {
		final View view = mToast.getView();
		view.setMinimumHeight(h);
	}

	private void setGravity(int gravity, int offsetX, int offsetY) {
		mToast.setGravity(gravity, offsetX, offsetY);
	}

	private void setDuration(int duration) {
		mToast.setDuration(duration);
	}

	private void setBackground(Drawable background) {
		mToast.getView().setBackground(background);
	}

	private void show() {
		if(Looper.myLooper() == Looper.getMainLooper()) {
			cancelLast(this);
			mToast.show();
		}
		else {
			mHandler.post(new Runnable() {
				@Override
				public void run() {
					show();
				}
			});
		}
	}

	private void cancel() {
		mHandler.removeCallbacks(mHide);
		mHandler.removeCallbacks(mShow);
		mToast.getView().removeOnAttachStateChangeListener(this);
		mToast.cancel();
	}

	private void postDelayed(Runnable r, long delayMillis) {
		mHandler.removeCallbacks(r);
		mHandler.postDelayed(r, delayMillis);
	}

	private final Runnable mShow = new Runnable() {
		@Override
		public void run() {
			if(SystemClock.uptimeMillis() < mFinishTime) {
				show();
				postDelayed(mShow, 500);
			}
		}
	};
	private final Runnable mHide = new Runnable() {
		@Override
		public void run() {
			cancel();
		}
	};

	@Override
	public void onViewAttachedToWindow(View v) {
		if(mFinishTime <= 0) {
			final int duration = mToast.getDuration();
			mFinishTime = SystemClock.uptimeMillis() + duration;
			if(duration > 500) {
				postDelayed(mShow, 500);
			}
			mHandler.postAtTime(mHide, mFinishTime);
		}
	}

	@Override
	public void onViewDetachedFromWindow(View v) {
		// nothing
	}
}
